![]() |
![]() |
|
Der Einsatz der Methoden ist ausgesprochen simpel. Legen Sie darauf Wert, die Zwischenablage nur dann auszuwerten, wenn sie ein bestimmtes Datenformat beherbergt, fragen Sie das mit einer der ContainsXxx-Methoden ab. Ist das Ergebnis positiv, also true, rufen Sie die Daten mit der entsprechenden GetXxx-Methode ab.
18.4.3 Mehrere Datenformate in der Zwischenablage
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void SetData(object data); |
| public void SetData(Type type, object data); |
| public void SetData(string format, object data); |
| public void SetData(string format, bool convert, object data); |
Dem string-Parameter können Sie auch in diesem Fall eine Konstante der Klasse DataFormats übergeben.
Der Einsatz der Methode ist sehr einfach. Zuerst erzeugen Sie ein DataObject-Objekt und rufen auf dessen Referenz die Methode SetData auf, der Sie jeweils Elemente unterschiedlichen Formats übergeben. Damit befindet sich der Inhalt natürlich noch nicht in der Zwischenablage, denn dazu ist der Aufruf der Methode SetDataObject der Clipboard-Klasse zuständig, der das DataObject-Objekt übergeben wird.
| DataObject data = new DataObject(); |
| data.SetData(DataFormats.Text, "Irgendeine Zeichenfolge"); |
| Clipboard.SetDataObject(data); |
Sollen mehrere unterschiedliche Formate der Zwischenablage übergeben werden, muss SetData mehrfach aufgerufen werden. Sehen wir uns dazu ein Beispiel an, bei dem der Zwischenablage sowohl ein Bitmap als auch eine Zeichenfolge übergeben wird.
| // -------------------------------------------------------------- |
| // Beispiel: ...\Kapitel 18\DataObjectDemo |
| // -------------------------------------------------------------- |
| public partial class Form1 : Form { |
| private Bitmap myBitmap; |
| public Form1() { |
| InitializeComponent(); |
| int width = pictureBox1.ClientSize.Width; |
| int height = pictureBox1.ClientSize.Height; |
| DataObject data = new DataObject(); |
| // Bitmap erzeugen |
| myBitmap = new Bitmap(width, height); |
| Graphics g = Graphics.FromImage(myBitmap); |
| g.FillRectangle(new SolidBrush(Color.White), 0, 0, width, height); |
| g.DrawLine(new Pen(Color.Blue, 4), 0, 0, width, height); |
| g.DrawLine(new Pen(Color.Red, 4), width, 0, 0, height); |
| // Bitmap in die Zwischenablage kopieren |
| data.SetData(DataFormats.Bitmap, myBitmap); |
| // zusätzlichen Text in die Zwischenablage kopieren |
| data.SetData(DataFormats.Text, "Feuchtfröhliche Feier"); |
| // DataObject-Objekt der Zwischenablage übergeben |
| Clipboard.SetDataObject(data); |
| } |
| private void btnShowClipboard_Click(object sender, EventArgs e) { |
| IDataObject dataObj = Clipboard.GetDataObject(); |
| // Bitmap aus der Zwischenablage in die Picturebox kopieren |
| if(dataObj.GetDataPresent(DataFormats.Bitmap)) |
| pictureBox1.Image = (Bitmap)dataObj.GetData(DataFormats.Bitmap); |
| // Text aus der Zwischenablage in die Textbox kopieren |
| if(dataObj.GetDataPresent(DataFormats.Text)) |
| textBox1.Text = (string)dataObj.GetData(DataFormats.Text); |
| } |
| } |
Im Konstruktor der Form wird nach der Initialisierungsroutine programmatisch ein Bitmap in weißer Hintergrundfarbe und mit zwei Diagonalen erzeugt. Das Bitmap wird dem DataObject-Objekt übergeben, zusätzlich auch noch eine Zeichenfolge. Zum Schluss wird das DataObject-Objekt in die Zwischenablage geschrieben.
Die Form enthält neben einer Schaltfläche eine Picturebox und eine Textbox. Wird auf die Schaltfläche geklickt, wird der Inhalt der Zwischenablage einer Typuntersuchung unterzogen mit dem Ergebnis, dass das Bitmap in der Picturebox angezeigt wird und die Zeichenfolge in der Textbox (siehe Abbildung 18.9).

Hier klicken, um das Bild zu vergrößern
Abbildung 18.9 Ausgabe des Beispielprogramms »DataObjectDemo«
Schließen Sie die Anwendung, geht der Inhalt der Zwischenablage verloren. Wollen Sie, dass beispielsweise das Bitmap auch danach noch von einer anderen Anwendung wie MS Paint aus der Zwischenablage geholt werden kann, muss das DataObject-Object mit
| Clipboard.SetDataObject(data, true); |
der Zwischenablage übergeben werden.
Die Klasse DataFormats definiert eine Reihe von Formaten. Sie sind aber nicht ausschließlich an diese Liste gebunden, sondern können auch eigene Datentypen in die Zwischenablage kopieren. Dabei kommt die dreiparametrige Variante der Methode SetData zum Einsatz. Der erste Parameter empfängt den Namen des neuen Datenformats, der boolesche Parameter gibt Auskunft darüber, ob die Konvertierung in ein anderes Format zulässig ist, und dem dritten Parameter werden die zu kopierenden Daten übergeben.
Nehmen wir an, es wäre der Typ ClassA wie folgt definiert:
| [Serializable] class ClassA { |
| public int Number; |
| public string Name; |
| } |
Beachten Sie, dass Typen, welche die Fähigkeit besitzen sollen, in die Zwischenablage kopiert zu werden, das Attribut Serializable aufweisen müssen.
Mit dem folgenden Code können wir ein Objekt des benutzerdefinierten Typs ClassA in die Zwischenablage kopieren:
| ClassA obj = new ClassA(); |
| obj.Number = 5500; |
| obj.Name = "Pelztier"; |
| DataObject data = new DataObject(); |
| data.SetData("ClassA", true, obj); |
| Clipboard.SetDataObject(data, true); |
Dem SetDataObject-Aufruf übergeben wir true. Daher kann auch nach dem Beenden der aktuellen Anwendung eine andere Anwendung die Daten auswerten – vorausgesetzt, der Anwendung ist der Typ ClassA bekannt.
Die Daten aus der Zwischenablage zu lesen, ist sehr einfach:
| IDataObject dataObj = Clipboard.GetDataObject(); |
| if(dataObj.GetDataPresent("ClassA")) { |
| ClassA obj = (ClassA)dataObj.GetData("ClassA"); |
| MessageBox.Show(obj.Number.ToString() + "\n" + obj.Name); |
| } |
Das Leeren der Zwischenablage erfolgt mit dem Aufruf der Methode Clear:
| Clipboard.Clear(); |
Kommen wir nun zum Ausgangspunkt zurück, der dazu führte, dass wir uns mit der Programmierung der Zwischenablage beschäftigt haben. Wir wollten einer Textbox ein Kontextmenü bereitstellen, in dem die Menüelemente Ausschneiden, Kopieren und Einfügen implementiert sind. Dazu ergänzen wir das in Abschnitt 18.2.6 begonnene Beispielprogramm, in dem wir auch noch nicht die gleichlautenden Untermenüs von Bearbeiten codiert haben.
| // -------------------------------------------------------------- |
| // Beispiel: ...\Kapitel 18\ContextMenuDemo |
| // -------------------------------------------------------------- |
| public Form1() { |
| InitializeComponent(); |
| Clipboard.Clear(); |
| } |
Der Konstruktor ist um eine Anweisung ergänzt, welche die Zwischenablage beim Start der Anwendung leert. Das ist keine Notwendigkeit, sondern dient nur dazu, das Verhalten des Menüelements Einfügen besser verfolgen zu können.
Sehen wir uns nun den Ereignishandler an, der markierten Text aus einer Textbox in die Zwischenablage schreibt.
| private void menuKopieren_Click(object sender, EventArgs e) { |
| Clipboard.SetText |
| (((TextBox)(((ToolStripContainer)this.ActiveControl). |
| ActiveControl)).SelectedText); |
| } |
Nur eine, wenn auch ausgesprochen lange Anweisung ist dazu da, nämlich der Aufruf der Methode SetText. Bevor der Methode aber die markierte Zeichenfolge übergeben werden kann, ist eine zweimalige Konvertierung notwendig. Hintergrund dafür ist, dass der Arbeitsbereich der Form vollständig durch einen anderen Container in Anspruch genommen wird, nämlich das ToolStripContainer-Objekt, in dem sich sämtliche Controls der Form versammeln, auch die beiden Textboxen.
Der einfache Aufruf von
| this.ActiveControl |
liefert dann nicht, wie zunächst zu erwarten wäre, die Referenz auf die Textbox, die offensichtlich aktiv ist, sondern die Referenz auf das ToolStripContainer-Objekt. Da wir über dieses Objekt an die Textbox gelangen wollen, ist die erste Konvertierung notwendig:
| (ToolStripContainer)this.ActiveControl |
Nun haben wir die gewünschte Referenz auf den ToolStripContainer, der als Containerelement seinerseits selbst die Eigenschaft ActiveControl aufweist. Da sich im Container nur zwei Textboxen befinden, können wir hier bedenkenlos in den Typ TextBox konvertieren.
| (TextBox)(((ToolStripContainer)this.ActiveControl).ActiveControl) |
Jetzt stehen uns alle Methoden und Eigenschaften einer Textbox zur Verfügung, von denen SelectedText die markierte Zeichenfolge liefert.
Eine ähnlich aufwändige Konvertierung ist auch zum Ausschneiden des markierten Textes notwendig, der anschließend mit SetText in die Zwischenablage geschrieben wird.
| private void menuAusschneiden_Click(object sender, EventArgs e) { |
| TextBox txt = (TextBox)((ToolStripContainer)this.ActiveControl).ActiveControl; |
| Clipboard.SetText(txt.SelectedText); |
| // Cursorposition merken |
| int cursorPosition = txt.SelectionStart; |
| this.Ausschneiden(txt); |
| // Eingabecursor positionieren |
| txt.SelectionStart = cursorPosition; |
| } |
Üblicherweise bleibt nach dem Ausschneiden der Cursor an seiner Position stehen. Deshalb merken wir uns in der Variablen cursorPosition diese und setzen nach der Zeichenfolgemanipulation den Cursor wieder passend ein. Würden wir darauf verzichten, wäre der Cursor vor dem ersten Zeichen positioniert.
Das Ausschneiden des markierten Textes und das neuerliche Zusammensetzen der Restzeichenfolge erfolgt in der Methode Ausschneiden. Diese erwartet die Referenz auf die Textbox, aus der die markierte Teilzeichenfolge ausgeschnitten werden soll.
| // Ausschneiden des markierten Texts |
| private void Ausschneiden(TextBox txt) { |
| int iLength = txt.SelectionLength + txt.SelectionStart; |
| txt.Text = txt.Text.Substring(0, txt.SelectionStart) + |
| txt.Text.Substring(iLength, txt.Text.Length – iLength); |
| } |
Das Einfügen eines Textes ist schon etwas aufwändiger. Wir müssen dabei zwei Dinge berücksichtigen:
| Ist kein Text in der Textbox markiert, in die der Inhalt der Zwischenablage geschrieben werden soll, wird die Position des Cursors als Einfügeposition bewertet. |
| Sollte in der Textbox Text markiert sein, muss dieser durch den Inhalt der Zwischenablage ersetzt werden. |
Nach dem Einfügen gilt es, die neue Zeichenfolge zu bilden und den Cursor an das Ende des eingefügten Textes zu setzen.
| private void menuEinfuegen_Click(object sender, EventArgs e) { |
| TextBox txt = |
| (TextBox)((ToolStripContainer)this.ActiveControl).ActiveControl; |
| // Cursorposition merken |
| int cursorPosition = txt.SelectionStart; |
| // falls markierter Text durch den Inhalt der Zwischenablage ersetzt werden soll |
| if (txt.SelectedText.Length > 0) |
| this.Ausschneiden(txt); |
| // Teilstrings links und rechts des Cursors bestimmen |
| string strLinks = txt.Text.Substring(0, cursorPosition); |
| string strRechts = txt.Text.Substring(cursorPosition, |
| txt.Text.Length – cursorPosition); |
| // Inhalt der Zwischenablage abrufen |
| string strClip = Clipboard.GetText(); |
| // neue Zeichenfolge zusammensetzen |
| txt.Text = strLinks + strClip + strRechts; |
| // Eingabecursor hinter dem eingefügten Text positionieren |
| txt.SelectionStart = cursorPosition + strClip.Length; |
| } |
Markierter Text wird mit dem Menüelement Löschen ausgeschnitten, aber nicht der Zwischenablage übergeben. Die Cursorposition ist anschließend zwischen den beiden verbleibenden Teilstrings. Für das Ausschneiden hatten wir weiter oben eine gleichnamige Methode bereitgestellt.
| private void menuLoeschen_Click(object sender, EventArgs e) { |
| TextBox txt = |
| (TextBox)((ToolStripContainer)this.ActiveControl).ActiveControl; |
| // Startposition des Cursors merken |
| int cursorPosition = txt.SelectionStart; |
| this.Ausschneiden(txt); |
| // Cursor setzen |
| txt.SelectionStart = cursorPosition; |
| } |
Unabhängig davon, ob der Benutzer sich des Anwendungs- oder Kontextmenüs bedient, um den Inhalt einer Textbox zu verändern, die Funktionalitäten Ausschneiden, Kopieren, Löschen und Einfügen bleiben dieselben. Daher werden die Click-Ereignisse der Menüelemente des Kontextmenüs mit den entsprechenden Ereignishandlern des Anwendungsmenüs verknüpft.
Das Ereignis DropDownOpening wird ausgelöst, ehe das angeklickte Menüelement sein Untermenü öffnet. Wir nutzen dieses Ereignis des Menüpunktes Bearbeiten, um festzustellen, ob
| sich einfügbarer Text in der Zwischenablage befindet. Wenn nicht, kann der Menüpunkt Einfügen deaktiviert werden. |
| in der aktiven Textbox kein Text markiert ist. In dem Fall gibt es nichts zu löschen, auszuschneiden oder in die Zwischenablage zu kopieren. Dann können die Menüpunkte Ausschneiden, Löschen und Kopieren deaktiviert angezeigt werden. |
Diese Prüfungen vollzieht der Ereignishandler des DropDownOpening-Ereignisses.
| private void menuBearbeiten_DropDownOpening(object sender, EventArgs e) { |
| TextBox txt = |
| (TextBox)((ToolStripContainer)this.ActiveControl).ActiveControl; |
| // Prüfen, ob sich in der Zwischenablage textuelle Daten befinden |
| if (!Clipboard.ContainsText()) |
| menuEinfuegen.Enabled = false; |
| else |
| menuEinfuegen.Enabled = true; |
| // Prüfen, ob Text in der aktiven Textbox markiert ist |
| if (txt.SelectedText == "") { |
| menuKopieren.Enabled = false; |
| menuAusschneiden.Enabled = false; |
| menuLoeschen.Enabled = false; |
| } |
| else { |
| menuKopieren.Enabled = true; |
| menuAusschneiden.Enabled = true; |
| menuLoeschen.Enabled = true; |
| } |
| } |
Analog wird auch die Aktivierung der Menüelemente des Kontextmenüs gesteuert. Dazu dient uns das Ereignis Opening.
| private void contextMenuStrip1_Opening(object sender, CancelEventArgs e) { |
| TextBox txt = |
| (TextBox)((ToolStripContainer)this.ActiveControl).ActiveControl; |
| // Prüfen, ob sich in der Zwischenablage textuelle Daten befinden |
| if (!Clipboard.ContainsText()) |
| conEinfuegen.Enabled = false; |
| else |
| conEinfuegen.Enabled = true; |
| // es ist kein Text in der aktiven Textbox markiert |
| if (txt.SelectedText == "") { |
| conKopieren.Enabled = false; |
| conAusschneiden.Enabled = false; |
| conLoeschen.Enabled = false; |
| } |
| else { |
| conKopieren.Enabled = true; |
| conAusschneiden.Enabled = true; |
| conLoeschen.Enabled = true; |
| } |
| } |
Kommen wir jetzt zum letzten Schritt. Im Kontextmenü wird ebenfalls die Änderung der Hintergrundfarbe angeboten. Wir müssen die Methode ChangeColor, die auch diesen Menüelementen als Ereignishandler dient, so ergänzen, dass eine Änderung der Farbe auch vom entsprechenden Kontextmenüelement verzeichnet wird.
| // Ereignishandler der Click-Ereignisse der Menüelemente, mit denen |
| // die Hintergrundfarbe der Textboxen geändert werden kann |
| private void ChangeColor(object sender, EventArgs e) { |
| foreach (ToolStripMenuItem temp in conHintergrundfarbe.DropDownItems) |
| temp.Checked = false; |
| foreach (ToolStripMenuItem temp in menuHintergrundfarbe.DropDownItems) |
| temp.Checked = false; |
| switch (((ToolStripMenuItem)sender).Text) { |
| case "Weiß": |
| txtOben.BackColor = Color.White; |
| txtUnten.BackColor = Color.White; |
| conWeiss.Checked = true; |
| menuWeiss.Checked = true; |
| break; |
| case "Rot": |
| ... |
| } |
| } |
| << zurück |
|
||||||||||||||
|
||||||||||||||
|
||||||||||||||
|
||||||||||||||
Copyright © Galileo Press 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.